/*
 * Microstate.cpp
 *
 *  Created on: Jul 11, 2013
 *      Author: x
 */
#include <vector>
#include <ctime>
#include <cstdlib>
#include <iterator>
#include <map>
#include <iostream>

#include "Microstate.h"
#include "Residue.h"
#include "Conformer.h"
//#include "Protein.h"

using namespace std;

namespace mcce {

Microstate::Microstate():eState(0.0) {

}

Microstate::Microstate(vector<Conformer*> &confs):eState(0.0) {
	conformers = confs;
}

Microstate::~Microstate() {
}

void Microstate::setRandomState(vector<Residue*> &residues) {
	conformers.clear();

	/*for (vector<Residue*>::iterator resIt=residues.begin(); resIt != residues.end(); resIt++) {
		if (!(*resIt)->isFixed()) {
			// It's Guaranteed that a free residue at least have one free conformer.
			vector<vector<Conformer*> >::iterator firstIt = (*resIt)->getGroupedFreeConf().begin();
			advance(firstIt, rand() % (*resIt)->getGroupedFreeConf().size());

			vector<Conformer*>::iterator secondIt = firstIt->begin();
			advance(secondIt, rand() % firstIt->size());

			conformers.push_back(*secondIt);
		}
	}*/
	for (vector<Residue*>::iterator resIt=residues.begin(); resIt != residues.end(); resIt++) {
		if (!(*resIt)->isFixed()) {
			vector<Conformer*>::iterator confIt = (*resIt)->getFreeConformers().begin();
			advance(confIt, rand()/(RAND_MAX/(*resIt)->getFreeConformers().size() + 1));

			conformers.push_back(*confIt);
		}
	}
}

Microstate& Microstate::nextRandomState(vector<Residue*> &residues) {
	vector<Residue*>::iterator resIt=residues.begin();
	vector<Residue*>::size_type resPos = rand() % residues.size();
	advance(resIt, resPos);


	vector<Conformer*>::iterator confIt = conformers.begin();
	advance(confIt, resPos);

	*confIt = (*resIt)->nextDiffConf(*confIt);

	//cout << "randomly selected residue: " << (*resIt)->getResName() << endl;
	//cout << "Its conformer changes to " << (*confIt)->getUniqId() << endl;


	if (rand() & 1) {   /* do multiple flip if odd number */
		// index the residues vector by residue name
		map<string, vector<Residue*>::size_type> resIndex;
		for (vector<Residue*>::size_type i=0; i<residues.size(); i++) {
			resIndex.insert(make_pair(residues[i]->getResName(), i));
		}

		vector<Residue*> freeNeighborRes;
		for (vector<Residue*>::iterator neighborResIt = (*resIt)->getNeighborRes().begin(); neighborResIt != (*resIt)->getNeighborRes().end(); neighborResIt++) {
			if (!(*neighborResIt)->isFixed()) {
				freeNeighborRes.push_back(*neighborResIt);
			}
		}

		vector<Residue*>::size_type monte_filps = 3;
		vector<Residue*>::size_type n_flip = monte_filps > freeNeighborRes.size() ? freeNeighborRes.size() : monte_filps;

		for (vector<Residue*>::size_type i=0; i<n_flip; i++) {
			vector<Residue*>::iterator neighborResIt = freeNeighborRes.begin();
			advance(neighborResIt, rand() % freeNeighborRes.size());

			// Have to make sure the neighbor residues are all free residues.

			resPos = resIndex[(*neighborResIt)->getResName()];

			resIt = residues.begin();
			advance(resIt, resPos);
			//cout << "Multiple flip select residue " << (*resIt)->getResName() << endl;
			confIt = conformers.begin();
			advance(confIt, resPos);
			//cout << "Conformer was " << (*confIt)->getUniqId();
			*confIt = (*resIt)->nextDiffConf(*confIt);
			//cout << ", Conformer is  " << (*confIt)->getUniqId() << endl;
		}
	}

	return *this;
}

float Microstate::calculateEState() {
	eState = 0.0;

	for (vector<Conformer*>::iterator firstIt = conformers.begin(); firstIt != conformers.end(); firstIt++) {
		eState += (*firstIt)->getESelf();
		for (vector<Conformer*>::iterator secondIt = conformers.begin(); secondIt != firstIt; secondIt++) {
			eState += (*firstIt)->getPairwise()[(*secondIt)->getUniqId()].sumPairwise;
		}
	}

	return eState;
}

Microstate& Microstate::operator =(Microstate &state) {
	if (this == &state) return *this;

	conformers = state.conformers;
	eState = state.eState;

	return *this;
}
} /* namespace mcce */
